#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <cstring>

#include <functional>
#include <thread>

#include "socket.hpp"

const int fdnums = 100000;

namespace YZC
{
    // 设置默认端口和最大backlog
    const int defaultPort = 8080;
    const int maxBacklog = 128;

    // 设置回调函数
    using func_t = std::function<int(int)>;

    class tcpServer
    {
    public:
        tcpServer(func_t func, int port = defaultPort)
            : _port(port), _epfd(-1), _callback(func) {}

        void init()
        {
            // epoll_create创建epollfd,初始化返回epoll_event数组
            _epfd = epoll_create(1);
            if (_epfd < 0)
            {
                printf("epoll_create err\n");
                exit(errno);
            }
            _events = new struct epoll_event[fdnums];

            // socket
            _listensock = mySocket::creatSockfd();

            // bind
            mySocket::Bind(_listensock, _port);

            // listen
            mySocket::Listen(_listensock, maxBacklog);

            // epollctl关心 listensock,注意要设置好event
            struct epoll_event ev;
            ev.data.fd = _listensock;
            ev.events = EPOLLIN;
            epoll_ctl(_epfd, EPOLL_CTL_ADD, _listensock, &ev);
        }

        void run()
        {
            while (true)
            {
                // epoll_wait唤醒就绪事件
                int n = epoll_wait(_epfd, _events, fdnums, -1);

                // 遍历_events执行fd对应方法
                for (int i = 0; i < n; i++)
                {
                    int fd = _events[i].data.fd;
                    int event = _events[i].events;
                    if (fd == _listensock)
                    {
                        // 说明监听事件就绪了，需要accept新连接
                        std::string ip;
                        uint16_t port;
                        int clientsock = mySocket::Accept(_listensock, ip, port);

                        // 然后epoll_ctl注册该事件
                        struct epoll_event ev;
                        ev.data.fd = clientsock;
                        ev.events = EPOLLIN;
                        epoll_ctl(_epfd, EPOLL_CTL_ADD, clientsock, &ev);
                    }
                    else if (event & EPOLLIN)
                    {
                        // 读事件就绪，这里直接使用回调函数简单处理
                        int n = _callback(fd);
                        if (n == 0)
                        {
                            close(fd);
                            epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
                        }
                    }
                    else if (event & EPOLLOUT)
                    {
                        // 写事件就绪
                    }
                    else // 其他事件就绪
                        ;
                }
            }
        }

    private:
        int _listensock; // 监听sock
        int _port;       // 端口port

        int _epfd;                   // epoll fd
        struct epoll_event *_events; // epoll返回数组
        func_t _callback;            // fd对应回调函数
    };

    int serviceIO(int sockfd)
    {
        // 这里仅做简单的数据收发
        char buffer[128] = {0};
        int count = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (count < 0)
        {
            std::cerr << "recv err" << std::endl;
            exit(-1);
        }
        if (count == 0)
        {
            // 对方关闭
            return 0;
        }
        printf("client --> server:%s\n", buffer);
        send(sockfd, buffer, strlen(buffer), 0);

        return count;
    }

    int serviceHTTP(int sockfd)
    {
        // 这里仅做简单的数据收发

        char buffer[128] = {0};
        int count = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (count < 0)
        {
            std::cerr << "recv err" << std::endl;
            exit(-1);
        }
        if (count == 0)
        {
            // 对方关闭
            return 0;
        }
        printf("client --> server:%s\n", buffer);

        std::string outbuffer;
        std::string body = "<h1>hello world</h1>";
        outbuffer =
            "HTTP/1.1 200 OK\r\n"
            "Content-Type: text/html; charset=utf-8\r\n"
            "Content-Length: " +
            std::to_string(body.size()) + "\r\n"
                                          "Server: Apache/2.4.41\r\n"
                                          "Date: Mon, 18 Dec 2023 08:32:10 GMT\r\n"
                                          "X-Frame-Options: DENY\r\n"
                                          "X-Content-Type-Options: nosniff\r\n"
                                          "Referrer-Policy: strict-origin-when-cross-origin\r\n"
                                          "\r\n" // 空行分隔头部和正文
            + body;

        // 无脑向客户端发送一个简单http响应
        send(sockfd, outbuffer.c_str(), outbuffer.size(), 0);
        return count;
    }

}
